package erwiki.ui.app.parts;

import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.Assert;
import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.e4.ui.di.Focus;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.services.IServiceConstants;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.service.UISession;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.browser.BrowserFunction;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
//import org.elwiki.api.IApplicationSession;
//import org.elwiki.api.IElWikiConstants;
//import org.elwiki.api.IWikiEngine;
//import org.elwiki.api.event.WikiPageRqEvent;
//import org.elwiki.api.exceptions.ProviderException;
import org.elwiki.editor.PageEditor;
//import org.elwiki.e4.ui.app.internal.bundle.AppUiActivator;
//import org.elwiki.editor.PageEditor;
import org.elwiki_data.PageReference;
import org.elwiki_data.WikiPage;
//import org.elwiki_data.provider.Elwiki_dataItemProviderAdapterFactory;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;

import erwiki.api.IErWikiConstants;
import erwiki.api.core.Engine;
import erwiki.api.exceptions.ProviderException;
import erwiki.api.exceptions.WikiException;
import erwiki.api.pages.Id2NamePage;
import erwiki.api.pages.PageManager;
import erwiki.api.render.RenderingManager;
import erwiki.api.rwc.RWC;
import erwiki.api.ui.PageCommand;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import jakarta.inject.Inject;
import jakarta.inject.Named;

public class WikiPageViewer {

	private static final Logger log = Logger.getLogger(WikiPageViewer.class);

	private static final String ATTR_PAGE_ID = "WikiPageViewer_ATTR_PAGE_ID";

	String ID = "org.elwiki.e4.ui.app.part.wikiPageViewer"; //$NON-NLS-1$

	@Inject
	EPartService partService;

	@Inject
	private IEventBroker eventBroker;

	@Inject
	private Engine engine;

	@Inject
	PageManager pageManager;

	@Inject
	private RenderingManager renderingManager;

	@Inject
	ESelectionService selectionService;

	// WORKAROUND public.
	private Browser browser;

	private String lastPage;

	private Action editItemAction;

	private SashForm sashForm;

	/** Область виджета редактора. */
	private Composite composite_l;

	private PageEditor wikipageEditor;

	private Composite composite_r;

	private Action switchShowRawText;
	private boolean isShowRawText = false;

	WikiPage selection = null;

	private CustomFunction function;

	/* :FVK: -- тестирование...
	EventHandler testHandler = new EventHandler() {
		@Override
		public void handleEvent(Event event) {
			System.out.println(event);
			Object part = event.getProperty(UIEvents.EventTags.ELEMENT);
			boolean tbr = (Boolean) event.getProperty(UIEvents.EventTags.NEW_VALUE);
			if (part instanceof MPart) {
				System.out.println("Part " + ((MPart) part).getElementId() + " is " + (!tbr ? "NOT" : "") + " visible");
			}
		}
	};
	eventBroker.subscribe(UIEvents.UIElement.ONTOP, testHandler);
	// TOPIC_TOBERENDERED TOPIC_VISIBLE
	 */

	/* :FVK: -- тестирование...
	@Inject
	@Optional
	private void subscribeTopicTodoUpdated(@UIEventTopic(UIEvents.Context.TOPIC_CONTEXT) Event event) {
		if (event == null) {
			return;
		}
	
		// The UI element
		Object element = event.getProperty(UIEvents.EventTags.ELEMENT);
		if(element instanceof PartImpl) {
			PartImpl part = (PartImpl) element;
			String uri = part.getContributionURI();
			System.out.println(uri);
		}
	
		// Rendered or hidden value
		// Boolean toBeRendered = (Boolean) event.getProperty(UIEvents.EventTags.NEW_VALUE);
	}
	 */

	// == CODE ================================================================

	/**
	 * Constructor.
	 */
	@Inject
	public WikiPageViewer() {
		// :FVK: this.appSession.getSessionMonitor().addWikiEventListener(this);
	}

	@Inject
	public void reactOnPart(@Optional @Named(IServiceConstants.ACTIVE_PART) MPart part) {
		// TODO: ...
		// :FVK:... отработать вывод Main страницы первый раз. (?если окно закрыли,открыли ...)
		// возможно это не надо.
		// -- ?отработать только при создании контента страницы.
		// Но если окно закрыли?
	}

	@Inject
	public void reactOnSelection(@Optional @Named(IServiceConstants.ACTIVE_SELECTION) WikiPage wikiPage,
			@Named(IServiceConstants.ACTIVE_PART) MPart activePart) {
		// Игнорировать свой вызов - избежать рекурсивной передачи выбранной страницы.
		if (wikiPage == null || activePart == null || this.getClass() == activePart.getObject().getClass()) {
			return;
		}
		this.selection = wikiPage;
		setPageContent(wikiPage.getId());
	}

	/*:FVK: -- old code -- инициализация страницы из предыдущей сессии.
	@Override
	public void init(IViewSite site, IMemento memento) throws PartInitException {
		super.init(site, memento);
		// :FVK: что это? (забыл)
		if (memento != null) {
			this.lastPage = memento.getString("lastPageID");
		} else {
			IWikiConfiguration wikiConfiguration = appSession.getWikiConfiguration();
			String frontPage = wikiConfiguration.getFrontPage();
			this.lastPage = frontPage;
		}
	}
	 */

	/**
	 * Create contents of the part.
	 *
	 * @param parent
	 * @wbp.parser.entryPoint
	 */
	@PostConstruct
	public void createPartControl(Composite parent) {
		Composite container = new Composite(parent, SWT.NONE);
		GridLayout gl_container = new GridLayout(1, false);
		container.setLayout(gl_container);

		{
			this.sashForm = new SashForm(container, SWT.NONE);
			GridData gd_sashForm = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
			gd_sashForm.heightHint = 277;
			this.sashForm.setLayoutData(gd_sashForm);
			{ // левая сторона (редактор страницы).
				this.composite_l = new Composite(this.sashForm, SWT.NONE);
				this.composite_l.setLayout(new GridLayout(1, false));
				{
					this.wikipageEditor = new PageEditor(this.composite_l, SWT.BORDER, pageManager);
					GridData gd_textEditing = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
					gd_textEditing.heightHint = 195;
					this.wikipageEditor.setLayoutData(gd_textEditing);
					this.wikipageEditor.addSaveEventHandler(
							java.beans.EventHandler.create(ActionListener.class, this, "editSave"));
					this.wikipageEditor.addCancelEventHandler(
							java.beans.EventHandler.create(ActionListener.class, this, "editCancel"));
				}
				{
					this.tableViewerRefs = new TableViewer(this.composite_l, SWT.BORDER | SWT.FULL_SELECTION);
					this.tableRefs = this.tableViewerRefs.getTable();
					GridData gd_table = new GridData(SWT.FILL, SWT.BOTTOM, true, false, 1, 1);
					gd_table.heightHint = 105;
					this.tableRefs.setLayoutData(gd_table);
					{
						this.tableViewerRefsColumn_0 = new TableViewerColumn(this.tableViewerRefs, SWT.NONE);
						this.tableRefsColumn_0 = this.tableViewerRefsColumn_0.getColumn();
						this.tableRefsColumn_0.setWidth(30);
						this.tableRefsColumn_0.setText("#");
					}
					{
						this.tableViewerRefsColumn_1 = new TableViewerColumn(this.tableViewerRefs, SWT.NONE);
						this.tableRefsColumn_1 = this.tableViewerRefsColumn_1.getColumn();
						this.tableRefsColumn_1.setWidth(500);
						this.tableRefsColumn_1.setText("name");
					}
				}
			}
			{ // правая сторона.
				this.composite_r = new Composite(this.sashForm, SWT.NONE);
				this.composite_r.setLayout(new FillLayout(SWT.HORIZONTAL));
				{
					this.sashForm_r = new SashForm(this.composite_r, SWT.NONE);
					{
						this.browser = new Browser(this.sashForm_r, SWT.NONE);
					}
					{
						this.textPage = new Text(this.sashForm_r, SWT.BORDER | SWT.MULTI);
						this.textPage.setVisible(true);
					}
					this.sashForm_r.setWeights((this.isShowRawText) ? new int[] { 50, 50 } : new int[] { 100, 0 });
				}
			}
			// :FVK: this.sashForm.setWeights(new int[] { 1, 1 });
		}

		/*:FVK:
		createActions();
		initializeToolBar();
		initializeMenu();
		 */

		// :FVK: initializeControls();

		this.composite_l.setVisible(false);
		this.sashForm.setWeights(new int[] { 1, 1 });

		// :FVK: -- old code
		// getSite().setSelectionProvider(this);

		this.function = new CustomFunction(this.browser, "theJavaFunction");

		// --------------------------------------------------------------------

		activateBrowser();
	}

	@PreDestroy
	public void dispose() {
		// nothing to do.
	}

	@Focus
	public void setFocus() {
		this.browser.setFocus();
	}

	/**
	 * Выводит в 'браузер' главную страницу.</br>
	 * FIXME: доработать - выводить страницу, которая выводилась последней в предыдущем сеансе.
	 */
	private void activateBrowser() {
		// trackOpenChatEditors(part);
		String pageId = null;

		pageId = pageManager.getMainPageId();
		/* :FVK: - старый e3 ElWiki
		if (WikiPageViewer.this.selection != null
				&& !((IStructuredSelection) WikiPageViewer.this.selection).isEmpty()) {
			WikiPage wp = (WikiPage) ((IStructuredSelection) WikiPageViewer.this.selection).getFirstElement();
			IWikiEngine wikiEngine = WikiPageViewer.this.appSession.getWikiEngine();
			pageId = wikiEngine.getPageId(wp);
		} else {
			pageId = pageManager.getMainPageCdoId();
		}
		 */

		if (pageId != null) {
			setPageContent(pageId);
		}
	}

	private class ErwikiUrl {
		final String path;
		Map<String, String> params = new HashMap<>();
		final String anchor;

		ErwikiUrl(String url) {
			String str = url;
			String[] res;

			// Извлечение Anchor.
			res = str.split("#");
			if (res.length > 1) {
				str = res[0];
				anchor = res[1];
			} else {
				anchor = null;
			}

			// Извлечение параметров.
			res = str.split("\\?");
			if (res.length > 1) {
				str = res[0];
				for (String param : res[1].split("&")) {
					res = param.split("=");
					if (res.length == 2 && StringUtils.isNotBlank(res[0])) {
						params.put(res[0], res[1]);
					}
				}
			}

			// Извлечение Path.
			int startPath = str.indexOf("//");
			if (startPath >= 0) {
				str = str.substring(startPath + 2);
			}
			path = str;
		}

		String getParam(String paramName) {
			return this.params.get(paramName);
		}
	}

	private class CustomFunction extends BrowserFunction {

		private final Logger log = Logger.getLogger(CustomFunction.class);

		/**
		 * Constructor.
		 *
		 * @param browser
		 * @param name
		 */
		CustomFunction(Browser browser, String name) {
			super(browser, name);
		}

		/**
		 * Выводит заданную страницу в компонент-браузер.
		 *
		 * @param arguments Ссылка на страницу ErWiki. Например, erwiki://?pgid=1003
		 */
		@Override
		public Object function(Object[] arguments) {
			{
				if (arguments.length == 1) {
					Object arg = arguments[0];
					if (arg instanceof java.lang.String inUrl) {
						ErwikiUrl url = new ErwikiUrl(inUrl);

						if (url.path.equals("create")) {
							// TODO: Выполнить команду 'Создать страницу'. Передать заданное имя, если есть.
							String pageName = url.getParam("name");
							try {
								pageName = engine.decodeName(pageName);
							} catch (IOException e) {
								log.error("Fail decode '" + pageName + "'", e);
							}
							return null;
						} else {
							// По умолчанию - вывести страницу с заданным pageId.
							// :FVK: а требуется ли: WikiPageViewer.this.setFocus();
							String pageId = url.getParam("pgid");
							selectCurrentPage(pageId);
							setPageContent(pageId, url.anchor);
						}
					}

					return null;
				}
			}
			// :FVK: -- old code
			// this.log.debug("theJavaFunction() called from javascript with args:");
			System.out.println("theJavaFunction() called from javascript with args:");

			StringBuffer buffer = new StringBuffer();
			buffer.append("theJavaFunction() called from javascript with args:\n");
			dumpArguments(arguments, "", buffer);
			String title = "BrowserFunction called";
			MessageDialog.openInformation(null, title, buffer.toString());

			Object returnValue = new Object[] { Short.valueOf("3"), Boolean.TRUE, null,
					new Object[] { "a string", Boolean.FALSE }, "hi", Float.valueOf(2.0f / 3.0f) };
			// int z = 3 / 0; // uncomment to cause a java error instead
			return returnValue;
		}

		private void dumpArguments(Object[] arguments, String tabString, StringBuffer buffer) {
			String tab = tabString + "    ";
			for (int i = 0; i < arguments.length; i++) {
				Object arg = arguments[i];
				if (arg == null) {
					buffer.append(tab);
					buffer.append("-->null\n");
				} else {
					buffer.append(tab);
					buffer.append("-->");
					buffer.append(arg.getClass().getName());
					buffer.append(": ");

					String a = arg.toString();

					buffer.append(arg.toString());
					buffer.append("\n");
					if (arg.getClass().isArray()) {
						Object[] arg1 = (Object[]) arg;
						dumpArguments(arg1, tab, buffer);
					}
				}
			}
		}
	}

	/**
	 * Returns the image descriptor with the given relative path.
	 */
	private ImageDescriptor getImageDescriptor(String relativePath) {
		// lCustomAction.setImageDescriptor(Activator.getImageDescriptor("icons/bomb.png"));

		String iconPath = "icons/";
		try {
			Bundle bundle = FrameworkUtil.getBundle(this.getClass());
			URL installURL = bundle.getEntry("/");
			URL url = new URL(installURL, iconPath + relativePath);
			return ImageDescriptor.createFromURL(url);
		} catch (MalformedURLException e) {
			// should not happen
			return ImageDescriptor.getMissingImageDescriptor();
		}
	}

	// == Таблица ссылок страницы =============================================

	protected WikiPage editingPage;

	private Table tableRefs;
	private TableViewer tableViewerRefs;
	private TableColumn tableRefsColumn_0;
	private TableViewerColumn tableViewerRefsColumn_0;
	private TableColumn tableRefsColumn_1;
	private TableViewerColumn tableViewerRefsColumn_1;
	private Text textPage;

	private SashForm sashForm_r;

	private ComposedAdapterFactory composedAdapterFactory;

	class PagesLinksTableLabelProvider extends LabelProvider implements ITableLabelProvider {
		private static final long serialVersionUID = -5564357223265889570L;

		@Override
		public Image getColumnImage(Object element, int columnIndex) {
			return null;
		}

		@Override
		public String getColumnText(Object element, int columnIndex) {
			String result = "";

			if (element instanceof PageReference) {
				PageReference pageReference = (PageReference) element;

				switch (columnIndex) {
				case 0: {
					WikiPage wikiPage = pageReference.getWikipage();
					int idx = wikiPage.getPageReferences().indexOf(pageReference);
					result = String.valueOf(idx);
				}
					break;

				case 1: {
					String pageId = pageReference.getPageId();
					// Engine engine = appSession.getWikiEngine();
					Id2NamePage id2NamePage = engine.getManager(Id2NamePage.class);
					result = id2NamePage.getName(pageId);
				}
					break;

				default:
					result = "--";
					break;
				}

			}

			return result;
		}
	}

	// ========================================================================

	/**
	 * Переключение состояния enabled/diabled действия "EDIT" (в меню, toolbar).
	 *
	 * @param state
	 */
	protected void switchEditAction(boolean state) {
		// FVK: временно не использовать: this.editItemAction.setEnabled(state);
	}

	public void startEditPage() {
		switchEditAction(false);

		UISession uiSession = RWT.getUISession();
		String pageId = (String) uiSession.getAttribute(ATTR_PAGE_ID);

		WikiPage wikiPage;
		try {
			wikiPage = pageManager.getPageById(pageId);
		} catch (ProviderException e) {
			log.error("Fail get page.", e);
			return;
		}
		this.editingPage = wikiPage;
		String content = wikiPage.getContentText();

		// setup widgets
		this.wikipageEditor.setText(content);

		this.tableViewerRefs.setContentProvider(new ArrayContentProvider());
		this.tableViewerRefs.setLabelProvider(new PagesLinksTableLabelProvider());
		this.tableViewerRefs.setInput(wikiPage.getPageReferences());

		// this.listViewer.setContentProvider(new ArrayContentProvider());
		// this.listViewer.setLabelProvider(new PagesListLabelProvider());
		// this.listViewer.setInput(wikiPage.getPagelink());

		// change widgets state
		this.composite_l.setVisible(true);
		this.sashForm.setWeights(new int[] { 50, 50 });

		RWT.getUISession().setAttribute(IErWikiConstants.ATTR_IS_EDITING, Boolean.TRUE);
	}

	/**
	 * Обработчик действия "EDIT SAVE".
	 */
	public void editSave() {
		switchEditAction(true);

		String newPageText = this.wikipageEditor.getText();
		try {
			// :FVK: putPageText(this.editingPage, newPageText);
			pageManager.saveText(newPageText, newPageText, newPageText);
		} catch (ProviderException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (WikiException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		RWT.getUISession().setAttribute(IErWikiConstants.ATTR_IS_EDITING, new Boolean(false));

		this.composite_l.setVisible(false);
		this.sashForm.setWeights(new int[] { 0, 100 });

		String id = this.editingPage.getId();
		setPageContent(id);
	}

	/**
	 * Обработчик действия "EDIT CANCEL".
	 */
	public void editCancel() {
		switchEditAction(true);

		RWT.getUISession().setAttribute(IErWikiConstants.ATTR_IS_EDITING, Boolean.FALSE);

		this.composite_l.setVisible(false);
		this.sashForm.setWeights(new int[] { 0, 100 });
	}

	protected void selectCurrentPage(String pageId) {
		try {
			Object object = pageManager.getPageById(pageId);
			selectionService.setSelection(object);
		} catch (ProviderException e) {
		}
	}

	/**
	 * Выводит содержимое заданной страницы в widget-браузер.</br>
	 * Выводится последняя версия страницы.
	 *
	 * @param pageId    Идентификатор страницы.
	 * @param argAnchor Якорь, до которого надо прокрутить вывод содержимого страницы.
	 */
	protected void setPageContent(String pageId, String... argAnchor) {
		RWT.getUISession().setAttribute(ATTR_PAGE_ID, pageId);
		String anchor = (argAnchor == null || argAnchor.length == 0) ? null : argAnchor[0];

		// TODO: проверить, есть ли страница - если нет,
		// то вместо предполагаемого содержимого выдать сообщение об ее отсутствии.
		WikiPage wikiPage;
		try {
			wikiPage = pageManager.getPageById(pageId);
		} catch (ProviderException e) {
			log.error("Fail get page.", e);
			return;
		}

		RWC.INSTANCE.setCommand(PageCommand.VIEW);
		RWC.INSTANCE.setPage(wikiPage);
		RWC.INSTANCE.setPageVersion(wikiPage.getLastVersion());

		// :FVK: --было-- final WikiContext context = Wiki.context().create(engine, wikiPage);
		// context.setRequestContext(WikiContext.PAGE_NONE);

		String scrollScript = null;
		// anchor = "section-Main-EndPage";
		anchor = "section-Main-_D0_9F_D0_BE_D0_B7_D0_B4_D1_80_D0_B0_D0_B2_D0_BB_D1_8F_D0_B5_D0_BC";
		if (anchor != null) {
			// JavaScript - сдвигает страницу к требуемому якорю (anchor).
			scrollScript = """
					<script type="text/javascript">
						window.addEventListener("load", function(evt) {
					    	location.hash='#""" + anchor + "';\n" + """
					    });
					</script>""";
		}

		String pageContent = renderingManager.getHTML(wikiPage);
		pageContent = fillPage(pageContent, scrollScript);

		WikiPageViewer.this.browser.setText(pageContent);
		// WikiPageViewer.this.browser.setUrl("/page/" + pageId);

		// WORKAROUND
		String pageText = wikiPage.getContentText();
		this.textPage.setText(pageText);

		// :FVK: -- old code
		// setSelection(new StructuredSelection(wikiPage));
	}

	/**
	 * Подготавливает HTML страницу для браузера.</br>
	 * Дополняет контент управляющими тегами.
	 *
	 * @param pageContent
	 * @param scrollScript
	 * @return
	 */
	private String fillPage(String pageContent, String scrollScript) {
		String html = """
				<!DOCTYPE html>
				<html lang='en' default='en'>
				<head>
				<meta charset="utf-8">
				<meta http-equiv="x-ua-compatible" content="ie=edge" />
				<meta name="viewport" content="width=device-width, initial-scale=1" />

				<script type="text/javascript">//<![CDATA[
				/* Localized javascript strings: LocalizedStrings[] */
				/* TODO: <wiki:IncludeResources type="jslocalizedstrings"/> */
				String.I18N = LocalizedStrings;
				String.I18N.PREFIX = "javascript.";
				//]]></script>

				<link rel="stylesheet" type="text/css" media="screen, projection, print" id="main-stylesheet" href="/shapes/default/haddock.css">
				<script src="/scripts/haddock.js"></script>

				<script type="text/javascript">
				document.addEventListener('DOMContentLoaded', function () {
					var aLinks = document.getElementsByTagName("A");
					for (var i = 0, count = aLinks.length; i < count; i++) {
						if( aLinks[i].href.substr(0,7)=="erwiki:") {
							aLinks[i].onclick = function() {
								var result;
								try {
									result = theJavaFunction(event.target.href);
								} catch (e) {
									alert('a java error occurred: ' + e.message);
									return false;
								}
								return false;
							}
						}
					}
				});
				</script>
				""";
		if (scrollScript != null) {
			html += scrollScript;
		}

		html += """

				<!-- :FVK: workaround for debug: use pragma 'no-cache':
				<meta http-equiv="pragma" content="no-cache" />
				-->

				<meta name="theme-color" content="#ffffff">
				""";

		// TODO: передать контекстные параметры:
		/*
		<meta name="wikiContext" content='<wiki:Variable var="requestcontext" />' />
		<wiki:Permission permission="edit"><meta name="wikiEditPermission" content="true"/></wiki:Permission>
		<meta name="wikiBaseUrl" content='<wiki:BaseURL />' />
		<meta name="wikiPageUrl" content='<wiki:Link format="url" pageName="#$%"/>' />
		<meta name="wikiEditUrl" content='<wiki:EditLink format="url" pageName="#$%"/>' />
		<meta name="wikiCloneUrl" content='<wiki:EditLink format="url" pageName="#$%"/>&clone=<wiki:Variable var="pagename" />' />
		<meta name="wikiJsonUrl" content='<%= ContextUtil.findContext(pageContext).getURL( WikiContext.PAGE_NONE, "ajax" ) %>' /><%--unusual pagename--%>
		<meta name="wikiPageName" content='<wiki:Variable var="pagename" />' /><%--pagename without blanks--%>
		<meta name="wikiPageId" content='<wiki:Variable var="pageid" />' />
		<meta name="wikiUserName" content='<wiki:UserName />' />
		<meta name="wikiTemplateUrl" content='<wiki:Link format="url" templatefile="" />' />
		<meta name="wikiApplicationName" content='<wiki:Variable var="ApplicationName" />' />
		<%--CHECKME
		<wiki:link> seems not to lookup the right jsp from the right template directory
		EG when a templatefile is not present, the generated link should point to the default template.
		Solution for now: manually force the relevant links back to the default template
		--%>
		<meta name="wikiXHRSearch" content='<wiki:Link format="url" templatefile="AJAXSearch.jsp" />' />
		<meta name="wikiXHRPreview" content='<wiki:Link format="url" templatefile="AJAXPreview.jsp" />' />
		<meta name="wikiXHRCategories" content='<wiki:Link format="url" templatefile="AJAXCategories.jsp" />' />
		<meta name="wikiXHRHtml2Markup" content='<wiki:Link format="url" path="shapes/AJAXHtml2Markup.jsp" />' />
		<meta name="wikiXHRMarkup2Wysiwyg" content='<wiki:Link format="url" path="shapes/XHRMarkup2Wysiwyg.jsp" />' />
		 */

		html += """
				</head>

				<body class="context-PAGE_VIEW can-flex">
				<div class="page-content ">
				""";

		html += pageContent;

		html += """
				</div>
				</body>
				</html>
				""";

		return html;
	}

	/*:FVK: -- old code
	@Override
	public void actionPerformed(WikiEvent event) {
		// TODO Auto-generated method stub
		if (event instanceof WikiPageRqEvent) {
			processingWikiPageRqEvent((WikiPageRqEvent) event);
		}
	}
	 */

	/* :FVK: - код от E4, за 2019
	private void processingWikiPageRqEvent(WikiPageRqEvent rqEvent) {
		final String pageId = rqEvent.getPageId();
		final String sessionId = rqEvent.getSessionId();

		// -- update viewed raw text of page ------------------------
		IWikiEngine we = appSession.getWikiEngine();
		WikiPage wikiPage = we.getPageById(pageId);
		// вывод Raw (оригинальный) текст страницы.
		String text = we.getPureText(wikiPage);
		this.textPage.setText(text);

		System.out.printf("Selection: %s, %s (%s)\n", wikiPage.getId(), sessionId, wikiPage.getName());

		// :FVK: -- old code
		//setSelection(new StructuredSelection(wikiPage));
	}
	 */

	/* :FVK: -- old code
	@Override
	public void addSelectionChangedListener(ISelectionChangedListener listener) {
		this.selectionChangedListeners.add(listener);
		System.out.println("Add listener: " + listener);
	}*/

	/* :FVK: -- old code
	@Override
	public ISelection getSelection() {
		return this.selection;
	}*/

	/* :FVK: -- old code
	@Override
	public void removeSelectionChangedListener(ISelectionChangedListener listener) {
		this.selectionChangedListeners.remove(listener);
		System.out.println("removeSelectionChangedListener: " + listener);
	}*/

	/* :FVK: -- old code
	@Override
	public void setSelection(ISelection select) {
		WikiPage wp = (WikiPage) ((IStructuredSelection) select).getFirstElement();
		System.out.printf("WikiPageViewer#setSelection: %s, \"%s\"\n", wp.getId(), wp.getName());

		this.selection = select;
		final SelectionChangedEvent e = new SelectionChangedEvent(this, select);
		this.selectionChangedListeners.forEach((listener) -> {
			//			SafeRunnable.run(new SafeRunnable() {
			//				private static final long serialVersionUID = 1L;
			//
			//				public void run() {
			listener.selectionChanged(e);
			//				}
			//			});
		});
	}*/

	/* :FVK: -- old code
	@Override
	public Object getAdapter(@SuppressWarnings("rawtypes") Class key) {
		/ * TODO: feature request.
	 * if (IContentOutlinePage.class.equals(key)) {
			return showOutlineView() ? getContentOutlinePage() : null;
		} else* /
		if (IPropertySheetPage.class.equals(key)) {
			return getPropertySheetPage();
		}
		return super.getAdapter(key);
	}

	private IPropertySheetPage getPropertySheetPage() {
		PropertySheetPage propertySheetPage = new PropertySheetPage();
		propertySheetPage.setPropertySourceProvider(new AdapterFactoryContentProvider(getAdapterFactory()));

		return propertySheetPage;
	}*/

	/**
	 * Return an ComposedAdapterFactory for all registered modesl
	 *
	 * @return a ComposedAdapterFactory
	 */
	protected AdapterFactory getAdapterFactory() {
		if (this.composedAdapterFactory == null) {
			this.composedAdapterFactory = new ComposedAdapterFactory(
					ComposedAdapterFactory.Descriptor.Registry.INSTANCE);

			// this.composedAdapterFactory.addAdapterFactory(new ResourceItemProviderAdapterFactory());

			Assert.isTrue(false, "нет кода.");
			/* :FVK: - код от E4, за 2019
			this.composedAdapterFactory.addAdapterFactory(new Elwiki_dataItemProviderAdapterFactory());
			 */

			// this.composedAdapterFactory.addAdapterFactory(new ReflectiveItemProviderAdapterFactory());
		}
		return this.composedAdapterFactory;
	}

}
